package asteroids.util;

import asteroids.Util;
import be.kuleuven.cs.som.annotate.*;

/**
 * A class representing a 2-dimensional vector in the Asteroids OGP project
 * 
 * @author Michiel De Cuyper
 * @version 1.0
 * 
 */
@Value
public class Vector {

	/**
	 * Constructor for a vector
	 * 
	 * @param x
	 *            The x component
	 * @param y
	 *            The y component
	 */
	public Vector(double x, double y) {
		setX(x);
		setY(y);
	}

	/**
	 * Creates a new vector with x = 0 and y = 0
	 */
	public Vector() {
		this(0, 0);
	}

	/**
	 * 
	 * @return ...
	 *         | return x
	 */
	@Basic
	@Immutable
	public double getX() {
		return x;
	}

	/**
	 * 
	 * @param x
	 *            The x value to be set
	 * @post ...
	 *       | this.x == x
	 */
	@Raw
	public void setX(double x) {
		this.x = x;
	}

	/**
	 * The x value
	 */
	private double x;

	/**
	 * 
	 * @return ...
	 *         | return this.y
	 */
	@Basic
	@Immutable
	public double getY() {
		return y;
	}

	/**
	 * 
	 * @param y
	 *            The y value to be set
	 * @post ...
	 *       | this.y == y
	 */
	public void setY(double y) {
		this.y = y;
	}

	/**
	 * The y value
	 */
	private double y;

	/**
	 * 
	 * @param vector1
	 *            The first vector
	 * @param vector2
	 *            The second vector
	 * 
	 * @note x = vector1.getX() + vector2.getX()
	 * @note y = vector1.getY() + vector2.getY()
	 * @return ...
	 *         | new Vector(x,y)
	 */
	public static Vector add(Vector vector1, Vector vector2) {
		return new Vector(vector1.getX() + vector2.getX(), vector1.getY() + vector2.getY());
	}

	/**
	 * 
	 * @param vector1
	 *            The first vector
	 * @param vector2
	 *            The second vector
	 * 
	 * @return ...
	 *         | vector1.getX() * vector2.getX() + vector1.getY() * vector2.getY()
	 */
	public static double dotProduct(Vector vector1, Vector vector2) {
		return vector1.getX() * vector2.getX() + vector1.getY() * vector2.getY();
	}

	/**
	 * 
	 * @param vector
	 *            The vector to be scalar multiplied
	 * @param scalar
	 *            The scaling factor
	 * @return ...
	 *         | new Vector(vector.getX() * scalar, vector.getY() * scalar);
	 */
	public static Vector scalarProduct(Vector vector, double scalar) {
		Vector scaled = new Vector();
		scaled.setX(vector.getX() * scalar);
		scaled.setY(vector.getY() * scalar);
		return scaled;
	}

	/**
	 * 
	 * @return ..
	 *         | Math.atan(this.getY()/this.getX())
	 */
	public double getAngle() {
		double x = this.getX();
		double y = this.getY();
		if (Util.fuzzyEquals(x, 0) && Util.fuzzyEquals(y, 0)) return 0;
		else if (x < 0) {
			return Math.atan(y / x) + Math.PI;
		}
		else if (y < 0) {
			return Math.atan(y / x) + 2 * Math.PI;
		}
		else {
			return Math.atan(y / x);
		}
	}

	/**
	 * 
	 * @return ...
	 *         | return Math.sqrt(x * x + y * y);
	 */
	public double getNorm() {
		double x = this.getX();
		double y = this.getY();

		return Math.sqrt(x * x + y * y);
	}

}
